home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1994 October / Macformat17.cdr / Shareware City / Developers / shutdown-fx-20-c / sfx control app ƒ / Shell ƒ / help.c < prev    next >
Text File  |  1994-07-11  |  22KB  |  830 lines

  1. /**********************************************************************\
  2.  
  3. File:        help.c
  4.  
  5. Purpose:    This module handles displaying the different help windows.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program in a file named "GNU General Public License".
  19. If not, write to the Free Software Foundation, 675 Mass Ave,
  20. Cambridge, MA 02139, USA.
  21.  
  22. \**********************************************************************/
  23.  
  24. #include "help.h"
  25. #include "environment.h"
  26. #include "util.h"
  27. #include "buttons.h"
  28. #include "timing.h"
  29. #include "program globals.h"
  30.  
  31. #define DEAD_SPACE_TOP        10
  32. #define DEAD_SPACE_LEFT        10
  33. #define DEAD_SPACE_BOTTOM    27
  34. #define DEAD_SPACE_RIGHT    10
  35. #define    TEXT_RECT_WIDTH        405
  36. #define    TEXT_RECT_HEIGHT    250
  37. #define    BUTTON_WIDTH        60
  38. #define    BUTTON_HEIGHT        60
  39. #define    XREF_DEAD_SPACE_TOP    5
  40. #define XREF_TEXT_WIDTH        46
  41. #define    XREF_WIDTH            70
  42. #define    XREF_HEIGHT            17
  43. #define    XREF_GAP            5
  44.  
  45. #define MAX_MAIN_TOPICS        4
  46. #define    MAX_SUB_TOPICS        5
  47.  
  48. #define    MAX_XREFS            4
  49.  
  50. #define MAIN_TOPIC_ID        600
  51. #define FIRST_SUB_TOPIC_ID    610
  52.  
  53. #define theWindowWidth (boundsRect.right-boundsRect.left)
  54. #define theWindowHeight (boundsRect.bottom-boundsRect.top)
  55. #define CorrectTime 1
  56. #define SCROLL_BOX_SIZE        20
  57.  
  58. typedef unsigned char    **CharHandle;
  59.  
  60. typedef struct
  61. {
  62.     long            offset;
  63.     short            lineHeight;
  64.     short            fontDescent;
  65.     short            fontNum;
  66.     unsigned char    fontStyle;
  67.     unsigned char    unused1;
  68.     short            fontSize;
  69.     short            unused2;
  70.     short            unused3;
  71.     short            unused4;
  72. } OneStyle;
  73.  
  74. typedef struct
  75. {
  76.     short        numStyles;
  77.     OneStyle    theStyle[31];
  78. } StylRec, *StylPtr, **StylHandle;
  79.  
  80. enum
  81. {
  82.     kLeft=0,
  83.     kCenter
  84. };
  85.  
  86. short            gNumMainTopics;
  87. short            gNumSubTopics[MAX_MAIN_TOPICS];
  88. short            gNumXRefs[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  89.  
  90. CIconHandle        gMainTopicIconColor[MAX_MAIN_TOPICS];
  91. Handle            gMainTopicIconBW[MAX_MAIN_TOPICS];
  92. Str31            gMainTopicTitle[MAX_MAIN_TOPICS];
  93. Rect            gMainTopicRect[MAX_MAIN_TOPICS];
  94.  
  95. CIconHandle        gSubTopicIconColor[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  96. Handle            gSubTopicIconBW[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  97. Str31            gSubTopicTitle[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  98. Rect            gSubTopicRect[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  99. short            gSubTopicID[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  100.  
  101. short            gXRefIndex[MAX_MAIN_TOPICS][MAX_SUB_TOPICS][MAX_XREFS];
  102. Rect            gXRefRect[MAX_XREFS];
  103.  
  104. short            gStickyTopic;
  105. short            gStickySubTopic;
  106.  
  107. short            gMainTopicShowing;        /* saved in prefs file */
  108. short            gSubTopicShowing;        /* saved in prefs file */
  109.  
  110. Rect            gTextRect;
  111. CharHandle        gTheText;
  112. StylHandle        gTheStyle;
  113.  
  114. /*-----------------------------------------------------------------------------------*/
  115. /* internal stuff for help.c                                                         */
  116.  
  117. void SetupTheHelpWindow(WindowDataHandle theData);
  118. void ShutdownTheHelpWindow(WindowDataHandle theData);
  119. void InitializeTheHelpWindow(WindowDataHandle theData);
  120. void OpenTheHelpWindow(WindowDataHandle theData);
  121. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed);
  122. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc);
  123. void DrawTheHelpWindow(short theDepth);
  124. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  125.     short theMode, Rect theRect);
  126. void DrawTheShadowBox(Rect theRect);
  127. short ParseRawTitle(Str255 theTitle, short *xRef, short *numXRefs);
  128. void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  129.     Boolean updateNow);
  130. void PushInSubTopic(WindowDataHandle theData);
  131. void PullOutSubTopic(WindowDataHandle theData, short mainTopic);
  132. void HighlightSubTopic(WindowDataHandle theData, short mainTopic, short subTopic,
  133.     Boolean isHighlighted);
  134. void GetTextResources(short mainTopic, short subTopic);
  135. void DisposeTextResources(void);
  136. void FullScrollRight(GrafPtr sourceGrafPtr, GrafPtr destGrafPtr, Rect boundsRect);
  137. void CalculateXRefInfo(short index, short *mainTopic, short *subTopic, Str255 name);
  138.  
  139.  
  140. short HelpWindowDispatch(WindowDataHandle theData, short theMessage, unsigned long misc)
  141. {
  142.     unsigned char    theChar;
  143.     Point            thePoint;
  144.     short            theDepth;
  145.     
  146.     switch (theMessage)
  147.     {
  148.         case kUpdate:
  149.             theDepth=misc&0x7fff;
  150.             DrawTheHelpWindow(theDepth);
  151.             return kSuccess;
  152.             break;
  153.         case kKeydown:
  154.             theChar=misc&charCodeMask;
  155.             KeyPressedInHelpWindow(theData, theChar);
  156.             return kSuccess;
  157.             break;
  158.         case kMousedown:
  159.             thePoint.h=(misc>>16)&0x7fff;
  160.             thePoint.v=misc&0x7fff;
  161.             MouseClickedInHelpWindow(theData, thePoint);
  162.             return kSuccess;
  163.             break;
  164.         case kOpen:
  165.             OpenTheHelpWindow(theData);
  166.             return kSuccess;
  167.             break;
  168.         case kInitialize:
  169.             InitializeTheHelpWindow(theData);
  170.             return kSuccess;
  171.             break;
  172.         case kStartup:
  173.             SetupTheHelpWindow(theData);
  174.             return kSuccess;
  175.             break;
  176.         case kShutdown:
  177.             ShutdownTheHelpWindow(theData);
  178.             return kSuccess;
  179.             break;
  180.     }
  181.     
  182.     return kFailure;        /* revert to default processing for all other messages */
  183. }
  184.  
  185. void SetupTheHelpWindow(WindowDataHandle theData)
  186. {
  187.     short            i,j;
  188.     unsigned char    *helpStr="\pHelp";
  189.     Handle            temp;
  190.     short            iconID;
  191.     short            centeringOffset;
  192.     
  193.     temp=GetResource('STR#', MAIN_TOPIC_ID);
  194.     gNumMainTopics=**((short**)temp);
  195.     ReleaseResource(temp);
  196.     for (i=0; i<gNumMainTopics; i++)
  197.     {
  198.         temp=GetResource('STR#', FIRST_SUB_TOPIC_ID+i);
  199.         gNumSubTopics[i]=**((short**)temp);
  200.         ReleaseResource(temp);
  201.     }
  202.     centeringOffset=DEAD_SPACE_TOP;
  203.     for (i=0; i<gNumMainTopics; i++)
  204.     {
  205.         GetIndString(gMainTopicTitle[i], MAIN_TOPIC_ID, i+1);
  206.         iconID=ParseRawTitle(gMainTopicTitle[i], 0L, 0L);
  207.         if (gHasColorQD)
  208.         {
  209.             gMainTopicIconColor[i]=0L;
  210.             gMainTopicIconColor[i]=GetCIcon(iconID);
  211.         }
  212.         gMainTopicIconBW[i]=0L;
  213.         gMainTopicIconBW[i]=GetIcon(iconID);
  214.         SetRect(&gMainTopicRect[i], DEAD_SPACE_LEFT, centeringOffset+BUTTON_HEIGHT*i,
  215.             DEAD_SPACE_LEFT+BUTTON_WIDTH, centeringOffset+BUTTON_HEIGHT*(i+1));
  216.         
  217.         for (j=0; j<gNumSubTopics[i]; j++)
  218.         {
  219.             GetIndString(gSubTopicTitle[i][j], FIRST_SUB_TOPIC_ID+i, j+1);
  220.             iconID=ParseRawTitle(gSubTopicTitle[i][j], gXRefIndex[i][j], &(gNumXRefs[i][j]));
  221.             gSubTopicID[i][j]=iconID;
  222.             if (gHasColorQD)
  223.             {
  224.                 gSubTopicIconColor[i][j]=0L;
  225.                 gSubTopicIconColor[i][j]=GetCIcon(iconID);
  226.             }
  227.             gSubTopicIconBW[i][j]=0L;
  228.             gSubTopicIconBW[i][j]=GetIcon(iconID);
  229.             SetRect(&gSubTopicRect[i][j], DEAD_SPACE_LEFT+BUTTON_WIDTH*(j+1),
  230.                 centeringOffset+BUTTON_HEIGHT*i, DEAD_SPACE_LEFT+BUTTON_WIDTH*(j+2),
  231.                 centeringOffset+BUTTON_HEIGHT*(i+1));
  232.         }
  233.     }
  234.     
  235.     for (i=0; i<MAX_XREFS; i++)
  236.     {
  237.         SetRect(&gXRefRect[i], XREF_TEXT_WIDTH+DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  238.             i*(XREF_WIDTH+XREF_GAP), DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+XREF_DEAD_SPACE_TOP,
  239.             XREF_TEXT_WIDTH+DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  240.             i*(XREF_WIDTH+XREF_GAP)+XREF_WIDTH, DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+
  241.             XREF_DEAD_SPACE_TOP+XREF_HEIGHT);
  242.     }
  243.     
  244.     gTheText=gTheStyle=0L;
  245.     GoToPage(0L, gMainTopicShowing, gSubTopicShowing, FALSE);
  246.     
  247.     SetRect(&gTextRect, DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT, DEAD_SPACE_TOP,
  248.         DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+TEXT_RECT_WIDTH,
  249.         DEAD_SPACE_TOP+TEXT_RECT_HEIGHT);
  250.     
  251.     (**theData).maxDepth=8;
  252.     (**theData).windowWidth=DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  253.         TEXT_RECT_WIDTH+DEAD_SPACE_RIGHT;
  254.     (**theData).windowHeight=DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+DEAD_SPACE_BOTTOM;
  255.     (**theData).windowType=noGrowDocProc;    /* document-looking thing */
  256.     (**theData).hasCloseBox=TRUE;
  257.     (**theData).windowBounds.top=50;
  258.     (**theData).windowBounds.left=6;
  259.     SetIndWindowTitle(kHelp, helpStr);
  260. }
  261.  
  262. void ShutdownTheHelpWindow(WindowDataHandle theData)
  263. {
  264.     short            i,j;
  265.     
  266.     for (i=0; i<gNumMainTopics; i++)
  267.     {
  268.         if (gHasColorQD)
  269.             if (gMainTopicIconColor[i]!=0L)
  270.                 DisposeCIcon(gMainTopicIconColor[i]);
  271.         if (gMainTopicIconBW[i]!=0L)
  272.             ReleaseResource(gMainTopicIconBW[i]);
  273.         
  274.         for (j=0; j<gNumSubTopics[i]; j++)
  275.         {
  276.             if (gHasColorQD)
  277.                 if (gSubTopicIconColor[i][j]!=0L)
  278.                     DisposeCIcon(gSubTopicIconColor[i][j]);
  279.             if (gSubTopicIconColor[i][j]!=0L)
  280.                 ReleaseResource(gSubTopicIconColor[i][j]);
  281.         }
  282.     }
  283.     DisposeTextResources();
  284. }
  285.  
  286. void InitializeTheHelpWindow(WindowDataHandle theData)
  287. {
  288.     (**theData).initialTopLeft.v=(**theData).windowBounds.top-9;
  289.     (**theData).initialTopLeft.h=(**theData).windowBounds.left;
  290.     gStickyTopic=-1;
  291. }
  292.  
  293. void OpenTheHelpWindow(WindowDataHandle theData)
  294. {
  295.     (**theData).offscreenNeedsUpdate=TRUE;
  296. }
  297.  
  298. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed)
  299. {
  300.     short            oldTopic;
  301.     
  302.     ObscureCursor();
  303.     
  304.     switch (keyPressed)
  305.     {
  306.         case 0x1d:                                        /* right arrow */
  307.             if (gStickyTopic==-1)
  308.             {
  309.                 gSubTopicShowing++;
  310.                 if (gSubTopicShowing>=gNumSubTopics[gMainTopicShowing])
  311.                 {
  312.                     gSubTopicShowing=0;
  313.                     gMainTopicShowing++;
  314.                     if (gMainTopicShowing>=gNumMainTopics)
  315.                         gMainTopicShowing=0;
  316.                 }
  317.                 GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  318.             }
  319.             else
  320.             {
  321.                 if (gStickySubTopic!=-1)
  322.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  323.                 gStickySubTopic++;
  324.                 if (gStickySubTopic>=gNumSubTopics[gStickyTopic])
  325.                     gStickySubTopic=0;
  326.                 HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, TRUE);
  327.             }
  328.             break;
  329.         case 0x1c:                                        /* left arrow */
  330.             if (gStickyTopic==-1)
  331.             {
  332.                 gSubTopicShowing--;
  333.                 if (gSubTopicShowing<0)
  334.                 {
  335.                     gMainTopicShowing--;
  336.                     if (gMainTopicShowing<0)
  337.                         gMainTopicShowing=gNumMainTopics-1;
  338.                     gSubTopicShowing=gNumSubTopics[gMainTopicShowing]-1;
  339.                 }
  340.                 GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  341.             }
  342.             else
  343.             {
  344.                 if (gStickySubTopic!=-1)
  345.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  346.                 gStickySubTopic--;
  347.                 if (gStickySubTopic<0)
  348.                     gStickySubTopic=gNumSubTopics[gStickyTopic]-1;
  349.                 HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, TRUE);
  350.             }
  351.             break;
  352.         case 0x1e:                                        /* up arrow */
  353.             if (gStickyTopic!=-1)
  354.             {
  355.                 oldTopic=gStickyTopic;
  356.                 PushInSubTopic(theData);
  357.                 gStickyTopic=oldTopic-1;
  358.                 if (gStickyTopic<0)
  359.                     gStickyTopic=gNumMainTopics-1;
  360.             }
  361.             else gStickyTopic=gNumMainTopics-1;
  362.             
  363.             PullOutSubTopic(theData, gStickyTopic);
  364.             break;
  365.         case 0x1f:                                        /* down arrow */
  366.             if (gStickyTopic!=-1)
  367.             {
  368.                 oldTopic=gStickyTopic;
  369.                 PushInSubTopic(theData);
  370.                 gStickyTopic=oldTopic+1;
  371.                 if (gStickyTopic>=gNumMainTopics)
  372.                     gStickyTopic=0;
  373.             }
  374.             else gStickyTopic=0;
  375.             
  376.             PullOutSubTopic(theData, gStickyTopic);
  377.             break;
  378.         case 0x1b:                                        /* escape key */
  379.             if (gStickyTopic!=-1)
  380.                 PushInSubTopic(theData);
  381.             else CloseTheWindow(theData);
  382.             break;
  383.         case 0x03:
  384.         case 0x0d:
  385.             if (gStickyTopic==-1)
  386.             {
  387.                 gStickyTopic=gMainTopicShowing;
  388.                 PullOutSubTopic(theData, gStickyTopic);
  389.             }
  390.             else
  391.             {
  392.                 if (gStickySubTopic!=-1)
  393.                 {
  394.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  395.                     GoToPage(theData, gStickyTopic, gStickySubTopic, TRUE);
  396.                 }
  397.                 else PushInSubTopic(theData);
  398.             }
  399.             break;
  400.     }
  401. }
  402.  
  403. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc)
  404. {
  405.     short            newTopic;
  406.     Boolean            isColor;
  407.     short            i;
  408.     Str255            name;
  409.     short            newMain, newSub;
  410.     
  411.     isColor=((**theData).windowDepth>2);
  412.     newTopic=-1;
  413.     
  414.     for (i=0; i<gNumXRefs[gMainTopicShowing][gSubTopicShowing]; i++)
  415.     {
  416.         if (PtInRect(mouseLoc, &gXRefRect[i]))
  417.         {
  418.             CalculateXRefInfo(gXRefIndex[gMainTopicShowing][gSubTopicShowing][i],
  419.                 &newMain, &newSub, name);
  420.             
  421.             if ((newMain!=-1) && (newSub!=-1))
  422.             {
  423.                 if (Track3DButton(&gXRefRect[i], name, 0L, (**theData).windowDepth))
  424.                 {
  425.                     GoToPage(theData, newMain, newSub, TRUE);
  426.                     return;
  427.                 }
  428.             }
  429.         }
  430.     }
  431.     
  432.     for (i=0; i<gNumMainTopics; i++)
  433.     {
  434.         if (PtInRect(mouseLoc, &gMainTopicRect[i]))
  435.         {
  436.             newTopic=i;
  437.             i=gNumMainTopics;
  438.         }
  439.     }
  440.     
  441.     if (newTopic!=-1)
  442.     {
  443.         if (newTopic==gStickyTopic)
  444.             PushInSubTopic(theData);
  445.         else
  446.         {
  447.             if (gStickyTopic!=-1)
  448.                 PushInSubTopic(theData);
  449.             PullOutSubTopic(theData, newTopic);
  450.             gStickyTopic=newTopic;
  451.         }
  452.     }
  453.     
  454.     if ((gStickyTopic!=-1) && (newTopic==-1))
  455.     {
  456.         for (i=0; i<gNumSubTopics[gStickyTopic]; i++)
  457.         {
  458.             if (PtInRect(mouseLoc, &gSubTopicRect[gStickyTopic][i]))
  459.             {
  460.                 if (gStickySubTopic!=-1)
  461.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  462.                 gStickySubTopic=-1;
  463.                 
  464.                 if (Track3DButton(&gSubTopicRect[gStickyTopic][i],
  465.                     gSubTopicTitle[gStickyTopic][i], isColor ?
  466.                     (Handle)gSubTopicIconColor[gStickyTopic][i] :
  467.                     gSubTopicIconBW[gStickyTopic][i], (**theData).windowDepth))
  468.                 {
  469.                     newTopic=i;
  470.                     i=gNumSubTopics[gStickyTopic];
  471.                 }
  472.             }
  473.         }
  474.         if (newTopic!=-1)
  475.             GoToPage(theData, gStickyTopic, newTopic, TRUE);
  476.         else
  477.             PushInSubTopic(theData);
  478.     }
  479. }
  480.  
  481. void DrawTheHelpWindow(short theDepth)
  482. {
  483.     GrafPtr            curPort;
  484.     short            i,j;
  485.     Boolean            isColor;
  486.     Rect            tempRect;
  487.     Str255            theStr;
  488.     short            dummy1, dummy2;
  489.     
  490.     isColor=(theDepth>2);
  491.     
  492.     GetPort(&curPort);
  493.     EraseRect(&(curPort->portRect));
  494.     
  495.     DrawTheShadowBox(gTextRect);
  496.     if (gTheText!=0L)
  497.     {
  498.         tempRect=gTextRect;
  499.         InsetRect(&tempRect, 8, 4);
  500.         DrawTheText(gTheText, gTheStyle, kLeft, srcOr, tempRect);
  501.     }
  502.     
  503.     for (i=0; i<gNumMainTopics; i++)
  504.     {
  505.         Draw3DButton(&gMainTopicRect[i], gMainTopicTitle[i],
  506.             isColor ? (Handle)gMainTopicIconColor[i] : gMainTopicIconBW[i],
  507.             theDepth, (i==gStickyTopic));
  508.         if (i==gStickyTopic)
  509.         {
  510.             for (j=0; j<gNumSubTopics[i]; j++)
  511.             {
  512.                 Draw3DButton(&gSubTopicRect[i][j], gSubTopicTitle[i][j],
  513.                 isColor ? (Handle)gSubTopicIconColor[i][j] : gSubTopicIconBW[i][j],
  514.                 theDepth, (j==gStickySubTopic));
  515.             }
  516.         }
  517.     }
  518.     
  519.     for (i=0; i<gNumXRefs[gMainTopicShowing][gSubTopicShowing]; i++)
  520.     {
  521.         CalculateXRefInfo(gXRefIndex[gMainTopicShowing][gSubTopicShowing][i],
  522.             &dummy1, &dummy2, theStr);
  523.         Draw3DButton(&gXRefRect[i], theStr, 0L, theDepth, FALSE);
  524.     }
  525.     if (gNumXRefs[gMainTopicShowing][gSubTopicShowing]>0)
  526.     {
  527.         MoveTo(gXRefRect[0].left-XREF_TEXT_WIDTH, gXRefRect[0].bottom-5);
  528.         TextFont(geneva);
  529.         TextSize(9);
  530.         DrawString("\pSee also:");
  531.     }
  532. }
  533.  
  534. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  535.     short theMode, Rect theRect)
  536. {
  537.     short            i, numStyles;
  538.     long            textPos;
  539.     long            maxOffset;
  540.     Str255            thisLine;
  541.     Boolean            notDoneYet;
  542.     unsigned char    thisChar;
  543.     short            theRow, theCol;
  544.     unsigned char    lastEnd, thisEnd;
  545.     Boolean            overRun;
  546.     
  547.     numStyles=(**theStyleHandle).numStyles;
  548.     textPos=0L;
  549.     theRow=theRect.top+(**theStyleHandle).theStyle[0].fontDescent+1;
  550.     theCol=theRect.left;
  551.     thisLine[0]=0x00;
  552.     lastEnd=0;
  553.     for (i=0; i<numStyles; i++)
  554.     {
  555.         if (i==numStyles-1)
  556.             maxOffset=GetHandleSize(theText);
  557.         else
  558.             maxOffset=(**theStyleHandle).theStyle[i+1].offset;
  559.         
  560.         TextFont((**theStyleHandle).theStyle[i].fontNum);
  561.         TextFace((**theStyleHandle).theStyle[i].fontStyle);
  562.         TextSize((**theStyleHandle).theStyle[i].fontSize);
  563.         TextMode(theMode);
  564.         
  565.         while (textPos<maxOffset)
  566.         {
  567.             notDoneYet=TRUE;
  568.             while ((textPos<maxOffset) && (notDoneYet))
  569.             {
  570.                 thisChar=thisLine[++thisLine[0]]=(*theText)[textPos++];
  571.                 notDoneYet=((thisChar!=' ') && (thisChar!=0x0d));
  572.             }
  573.             
  574.             thisEnd=thisLine[0];
  575.             overRun=(theRect.right-theCol<=StringWidth(thisLine));
  576.             
  577.             if ((overRun) || (thisChar==0x0d) || (textPos==maxOffset))
  578.             {
  579.                 if (overRun)
  580.                     thisLine[0]=lastEnd;
  581.                 if (theJust==kCenter)
  582.                     MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  583.                             theCol, theRow);
  584.                 else
  585.                     MoveTo(theCol, theRow);
  586.                 theCol+=StringWidth(thisLine);
  587.                 DrawString(thisLine);
  588.                 if (overRun)
  589.                 {
  590.                     BlockMove(&thisLine[lastEnd+1], &thisLine[1], thisEnd-lastEnd+1);
  591.                     if (thisEnd>=lastEnd)
  592.                     {
  593.                         thisLine[0]=thisEnd-lastEnd-1;
  594.                         textPos--;
  595.                     }
  596.                     else
  597.                         thisEnd=thisLine[0]=0x00;
  598.                 }
  599.                 else thisLine[0]=0x00;
  600.                 if ((overRun) || (thisChar==0x0d))
  601.                 {
  602.                     theRow+=(**theStyleHandle).theStyle[i].lineHeight;
  603.                     theCol=theRect.left;
  604.                 }
  605.             }
  606.             
  607.             lastEnd=thisEnd;
  608.         }
  609.         
  610.         if (thisLine[0]!=0x00)
  611.         {
  612.             if (theJust==kCenter)
  613.                 MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  614.                         theCol, theRow);
  615.             else
  616.                 MoveTo(theCol, theRow);
  617.             theCol+=StringWidth(thisLine);
  618.             DrawString(thisLine);
  619.             thisLine[0]=0x00;
  620.         }
  621.     }
  622.     TextMode(srcOr);
  623. }
  624.  
  625. void DrawTheShadowBox(Rect theRect)
  626. {
  627.     theRect.right-=2;
  628.     theRect.bottom-=2;
  629.     FrameRect(&theRect);
  630.     MoveTo(theRect.left+3, theRect.bottom+1);
  631.     Line(theRect.right-theRect.left-2, 0);
  632.     Line(0, -theRect.bottom+theRect.top+3);
  633.     MoveTo(theRect.left+3, theRect.bottom);
  634.     Line(theRect.right-theRect.left-3, 0);
  635.     Line(0, -theRect.bottom+theRect.top+4);
  636. }
  637.  
  638. short ParseRawTitle(Str255 theTitle, short *xRef, short *numXRefs)
  639. {
  640.     Str255            numStr;
  641.     unsigned long    result;
  642.     short            i,j;
  643.     Boolean            gotbullet;
  644.     Boolean            moreXRefs;
  645.     
  646.     if (xRef!=0L)
  647.     {
  648.         *numXRefs=0;
  649.         for (j=1, gotbullet=FALSE; ((j<=theTitle[0]) && (!gotbullet)); j++)
  650.             gotbullet=(theTitle[j]=='%');
  651.         if (gotbullet)
  652.         {
  653.             i=j;
  654.             do
  655.             {
  656.                 numStr[0]=0x00;
  657.                 while ((numStr[0]<=theTitle[0]-i) &&
  658.                     (((numStr[numStr[0]]=theTitle[i+(numStr[0]++)]))!=' ')) {}
  659.                 if (numStr[numStr[0]]==' ')
  660.                 {
  661.                     moreXRefs=TRUE;
  662.                     i+=numStr[0];
  663.                     numStr[0]--;
  664.                 }
  665.                 else moreXRefs=FALSE;
  666.                 StringToNum(numStr, &result);
  667.                 xRef[(*numXRefs)++]=result;
  668.             }
  669.             while (moreXRefs);
  670.             theTitle[0]=j-2;
  671.         }
  672.     }
  673.     numStr[0]=0x00;
  674.     while ((numStr[numStr[0]]=theTitle[++numStr[0]])!=' ') {}
  675.     theTitle[0]-=numStr[0];
  676.     Mymemcpy(&theTitle[1], &theTitle[numStr[0]+1], theTitle[0]);
  677.     numStr[0]--;
  678.     StringToNum(numStr, &result);
  679.     return result;
  680. }
  681.  
  682. void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  683.     Boolean updateNow)
  684. {
  685.     DisposeTextResources();
  686.     GetTextResources(mainTopic, subTopic);
  687.     gMainTopicShowing=mainTopic;
  688.     gSubTopicShowing=subTopic;
  689.     gStickyTopic=gStickySubTopic=-1;
  690.     if (updateNow)
  691.     {
  692.         (**theData).offscreenNeedsUpdate=TRUE;
  693.         UpdateTheWindow(theData);
  694.     }
  695. }
  696.  
  697. void PushInSubTopic(WindowDataHandle theData)
  698. {
  699.     gStickyTopic=-1;
  700.     (**theData).offscreenNeedsUpdate=TRUE;
  701.     UpdateTheWindow(theData);
  702. }
  703.  
  704. void PullOutSubTopic(WindowDataHandle theData, short mainTopic)
  705. {
  706.     short            i;
  707.     short            theDepth;
  708.     Boolean            isColor;
  709.     Rect            tempRect;
  710.     
  711.     gStickySubTopic=-1;
  712.     
  713.     isColor=(theDepth=(**theData).windowDepth)>2;
  714.     
  715.     SetPortToOffscreen(theData);
  716.     for (i=0; i<gNumSubTopics[mainTopic]; i++)
  717.     {
  718.         Draw3DButton(&gSubTopicRect[mainTopic][i], gSubTopicTitle[mainTopic][i],
  719.         isColor ? (Handle)gSubTopicIconColor[mainTopic][i] :
  720.         gSubTopicIconBW[mainTopic][i], theDepth, FALSE);
  721.     }
  722.     RestorePortToScreen(theData);
  723.  
  724.     Draw3DButton(&gMainTopicRect[mainTopic], gMainTopicTitle[mainTopic],
  725.         isColor ? (Handle)gMainTopicIconColor[mainTopic] :
  726.         gMainTopicIconBW[mainTopic], theDepth, TRUE);
  727.     
  728.     tempRect=gSubTopicRect[mainTopic][0];
  729.     tempRect.right=gSubTopicRect[mainTopic][gNumSubTopics[mainTopic]-1].right;
  730.     FullScrollRight(GetOffscreenGrafPtr(theData), GetWindowGrafPtr(theData), tempRect);
  731.     
  732.     (**theData).offscreenNeedsUpdate=TRUE;
  733. }
  734.  
  735. void HighlightSubTopic(WindowDataHandle theData, short mainTopic, short subTopic,
  736.     Boolean isHighlighted)
  737. {
  738.     Draw3DButton(&gSubTopicRect[mainTopic][subTopic], gSubTopicTitle[mainTopic][subTopic],
  739.         ((**theData).windowDepth>2) ? (Handle)gSubTopicIconColor[mainTopic][subTopic] :
  740.         gSubTopicIconBW[mainTopic][subTopic], (**theData).windowDepth, isHighlighted);
  741.     
  742.     (**theData).offscreenNeedsUpdate=TRUE;
  743. }
  744.  
  745. void GetTextResources(short mainTopic, short subTopic)
  746. {
  747.     short            resID;
  748.     
  749.     DisposeTextResources();
  750.     resID=gSubTopicID[mainTopic][subTopic];
  751.     gTheText=GetResource('TEXT', resID);
  752.     gTheStyle=GetResource('styl', resID);
  753. }
  754.  
  755. void DisposeTextResources(void)
  756. {
  757.     if (gTheText!=0L)
  758.         ReleaseResource(gTheText);
  759.     if (gTheStyle!=0L)
  760.         ReleaseResource(gTheStyle);
  761.     gTheText=gTheStyle=0L;
  762. }
  763.  
  764. void FullScrollRight(GrafPtr sourceGrafPtr, GrafPtr destGrafPtr, Rect boundsRect)
  765. {
  766.     Rect            sourceRect, destRect, scrollRect;
  767.     short            BoxSize;
  768.     
  769.     StartTiming();
  770.     
  771.     BoxSize=SCROLL_BOX_SIZE;
  772.     
  773.     destRect=sourceRect=scrollRect=boundsRect;
  774.     destRect.right=destRect.left+BoxSize;
  775.     sourceRect.left=boundsRect.right-BoxSize;
  776.     scrollRect.right=scrollRect.left+2*BoxSize;
  777.     
  778.     CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  779.         &sourceRect, &destRect, 0, 0L);
  780.     
  781.     TimeCorrection(CorrectTime);
  782.     
  783.     while (scrollRect.right<=boundsRect.right)
  784.     {
  785.         StartTiming();
  786.         sourceRect.right-=BoxSize;
  787.         sourceRect.left-=BoxSize;
  788.         ScrollTheRect(&scrollRect, BoxSize, 0, 0L);
  789.         CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  790.             &sourceRect, &destRect, 0, 0L);
  791.         TimeCorrection(CorrectTime);
  792.         scrollRect.right+=BoxSize;
  793.     }
  794.     
  795.     if (scrollRect.right!=boundsRect.right)
  796.         CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  797.             &boundsRect, &boundsRect, 0, 0L);
  798. }
  799.  
  800. void CalculateXRefInfo(short index, short *mainTopic, short *subTopic, Str255 name)
  801. {
  802.     short            theMain, theSub;
  803.     unsigned char    *bad="\pBad XRef!";
  804.     
  805.     theMain=gNumMainTopics-1;
  806.     theSub=gNumSubTopics[theMain]-1;
  807.     while ((theMain>=0) && (index!=gSubTopicID[theMain][theSub]))
  808.     {
  809.         theSub--;
  810.         if (theSub<0)
  811.         {
  812.             theMain--;
  813.             theSub=gNumSubTopics[theMain];
  814.         }
  815.     }
  816.     
  817.     if (theMain<0)
  818.     {
  819.         Mymemcpy(name, bad, bad[0]+1);
  820.         *mainTopic=*subTopic=-1;
  821.     }
  822.     else
  823.     {
  824.         Mymemcpy(name, gSubTopicTitle[theMain][theSub],
  825.             gSubTopicTitle[theMain][theSub][0]+1);
  826.         *mainTopic=theMain;
  827.         *subTopic=theSub;
  828.     }
  829. }
  830.